package ysq.xyg.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import ysq.weixin.client.WxApiClient;
import ysq.weixin.client.WxMemoryCacheClient;
import ysq.weixin.model.Return_Notice_Pay;
import ysq.weixin.model.Return_pay;
import ysq.weixin.model.info.OAuthAccessToken;
import ysq.weixin.model.info.OAuthScope;
import ysq.weixin.model.info.User;
import ysq.weixin.util.WxUrlUtil;
import ysq.xyg.model.Member;
import ysq.xyg.model.PersonLevel;
import ysq.xyg.model.info.ReturnInfo;
import ysq.xyg.model.info.WxAccountInfo;
import ysq.xyg.service.*;
import ysq.xyg.util.BaseConstant;
import ysq.xyg.util.BaseUtil;
import ysq.xyg.util.DateUtil;
import ysq.xyg.util.ProProperties;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

/**
 * Created by Administrator on 2017/6/23 0023.
 */
@Controller
@RequestMapping("/weiXin")
public class WeXinController extends BaseController {

    private static final Logger log= LoggerFactory.getLogger(WeXinController.class);
    @Autowired
    private MemberService memberService;

    @Autowired
    private PersonLevelService personLevelService;
    @Autowired
    private BaseConfigService baseConfigService;
    /**
     * oauth2.0跳转入库
     * state:1.首页,2,添加页面
     * */
    @RequestMapping("/oauth/{state}")
    public ModelAndView oauth(HttpServletResponse response, HttpServletRequest request, @PathVariable String state) throws IOException {
        String oauthType = request.getParameter("oauthType");
        String scope= OAuthScope.Base.toString();
        if(OAuthScope.Userinfo.toString().equals(oauthType)){
            scope=OAuthScope.Userinfo.toString();
        }
        WxAccountInfo wxAccountInfo = WxMemoryCacheClient.getSingleWxAccountInfo();//获取缓存中的唯一账号
        String url = WxUrlUtil.getOAuthCodeUrl(wxAccountInfo.getAppid(), wxAccountInfo.getBaseURL()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL(),scope, state);
        return new ModelAndView("redirect:" + url);
    }

    /**
     * 获取openid 并跳转
     * */
    @RequestMapping("/acceptOpenid")
    public ModelAndView acceptOpenid(HttpServletResponse response, HttpServletRequest request) throws IOException {
        String code = request.getParameter("code");
        // 获取到的state是模式页面组合，模式由一个字符，1表示base,2表示userinfo,其他为页面标识符
        String scopeState = request.getParameter("state");
        String scope= scopeState.substring(0,1);
        String state = scopeState.substring(1,scopeState.length());
        log.info("scopeState is "+scopeState+"code is "+code+";state is "+state+";scope is "+scope);
        ModelAndView modelAndView=null;
        try {
            // 获取缓存中的唯一账号
            WxAccountInfo wxAccountInfo = WxMemoryCacheClient.getSingleWxAccountInfo();
            OAuthAccessToken oAuthAccessToken = WxApiClient.getOAuthOpenId(wxAccountInfo, code);
            log.info("openid is "+oAuthAccessToken.getOpenid());
            if (StringUtils.isEmpty(oAuthAccessToken.getOpenid())) {
                //跳转到oauth2.0的url
                String url = WxUrlUtil.getOAuthCodeUrl(wxAccountInfo.getAppid(), wxAccountInfo.getBaseURL()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL(),OAuthScope.Base.toString(), state);
                modelAndView =  new ModelAndView("redirect:" + url);
            }else{
                int num=0;
                //判断当前用户是否已经保存到数据库
                Member member = createUser(oAuthAccessToken,scope);
                if (member != null) {
                    modelAndView = acceptView(member,state, oAuthAccessToken);
                } else {
                    //跳转到oauth2.0的url
                    String url = WxUrlUtil.getOAuthCodeUrl(wxAccountInfo.getAppid(), wxAccountInfo.getBaseURL()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL(),OAuthScope.Userinfo.toString(), state);
                    modelAndView =  new ModelAndView("redirect:" + url);
                }
                return modelAndView;
            }
        } catch (Exception e) {
            //跳转错误页面
            e.printStackTrace();
        }
        return modelAndView;
    }
    protected ModelAndView acceptView(Member member, String state,OAuthAccessToken oAuthAccessToken){
        ModelAndView modelAndView=null;
        if (BaseConstant.WX_STATE_ONE.equals(state)) {
            modelAndView = new ModelAndView("redirect:"+ProProperties.getInstance().getWxOauthRredirectIndexURL(member.getId()));
        } else {
            //默认页面
            modelAndView = new ModelAndView("redirect:"+ProProperties.getInstance().getWxOauthRredirectIndexURL(member.getId()));
        }
        return  modelAndView;
    }

    /**
     * 创建本地用户
     * @param oAuthAccessToken
     * @param scope
     * @return
     */
    protected Member createUser(OAuthAccessToken oAuthAccessToken,String scope){
        Member member=memberService.selectEntityByOpenid(oAuthAccessToken.getOpenid());
        if(member == null){
            // 用户不存在
            if(BaseConstant.OAUTH_USERINFO.equals(scope)){
                //Oauth为获取用户信息模式
                User user=WxApiClient.getOAuthUserInfo(oAuthAccessToken);
                if(user!=null){
                    //将用户信息插入数据库
                    int cardNo = memberService.selectMaxId();
                    if (cardNo < BaseConstant.MEMBER_MIN_DEFAULT_ID) {
                        cardNo = BaseConstant.MEMBER_MIN_DEFAULT_ID;
                    } else {
                        cardNo = cardNo + 1;
                    }
                    member=new Member();
                    member.setId(BaseUtil.uId());
                    member.setOpenid(user.getOpenid());
                    member.setCardNo(String.valueOf(cardNo));
                    member.setStatus("2");
                    member.setMoney(0.0);
                    member.setHeadImage(user.getHeadlogo());
                    member.setNickName(BaseUtil.encodeBase64String(user.getNickname()));
                    member.setCreateTime(new Date());
                    try {
                        int id=memberService.insert(member);
                        if(id>0){
                            return member;
                        }
                    }catch (Exception e){
                        return null;
                    }

                }
            }
            return null;
        }else{
            //用户存在
            return member;
        }
    }


    /**
     * 微信支付
     * */
    @RequestMapping(value = "/pay",method = RequestMethod.POST)
    public @ResponseBody
    JSONObject Pay(double money, String openid, String params, String desc, HttpServletRequest request){
        ReturnInfo returnInfo=new ReturnInfo();
        JSONObject jsonObject=new JSONObject();
        if(StringUtil.isNotEmpty(openid) && money > 0){
            //获取订单号
            String id="E"+new Date().getTime()+ BaseUtil.getRandom(6,BaseUtil.NUMBER_CONTENT);
            //获取时间戳
            String timeStamp= DateUtil.create_timestamp();
            //获取ip地址
            String ip= request.getRemoteAddr();
            WxAccountInfo wxAccountInfo = WxMemoryCacheClient.getSingleWxAccountInfo();//获取缓存中的唯一账号
            Return_pay pay=WxApiClient.WeiXin(params,"账户充值"+money+"元",(int)(money*100), openid,wxAccountInfo.getBaseURL()+ProProperties.getInstance().getWxPayRequestURL(),id,ip,timeStamp,wxAccountInfo.getAppid(),wxAccountInfo.getPayMchId(),wxAccountInfo.getPayKey());
            pay.setId(id);
            log.info(pay.toString());
            if(pay==null||"".equals(pay)){
                returnInfo=new ReturnInfo(BaseConstant.FAIL,BaseConstant.WECHAT_PAY_FAILL);
            }else{
                returnInfo.setResult(pay);
            }
        }else{
            returnInfo=new ReturnInfo(BaseConstant.FAIL,BaseConstant.DATABASE_ERROR_CANSHU);
        }
        jsonObject.put("returnInfo",returnInfo);
        return jsonObject;
    }

    @RequestMapping(value = "/test")
    public @ResponseBody
    void test(String recordId,String payNo){
        resultDo(recordId,payNo);
    }
    /**
     * 微信支付发货通知
     * */
    @RequestMapping(value = "/pay/sendNotice")
    public void sendNotice( HttpServletRequest request,HttpServletResponse response) throws IOException {
        response.setContentType("text/xml;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        request.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        StringBuilder buff = new StringBuilder();
        buff.append("<?xml version= \"1.0\" encoding=\"utf-8\"?>");

        String postStr=null;
        try{
            postStr=this.readStreamParameter(request.getInputStream());
        }catch(Exception e){
            log.error("Error SendProductNoticeServiceImpl method get postStr:"+ e);
        }
        Return_Notice_Pay pay=new Return_Notice_Pay();
        if (null!=postStr&&!postStr.isEmpty()){
            Document document=null;
            try{
                document = DocumentHelper.parseText(postStr);
            }catch(Exception e){
                log.error("Error SendProductNoticeServiceImpl method get document:"+ e);
            }
            if(null==document){
                buff.append("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>");
                out.print(buff.toString());
                return;
            }
            Element root=document.getRootElement();
            String return_code = root.elementText("return_code");
            log.info("return_code:"+return_code);
            pay.setReturn_code(return_code);
            if("SUCCESS".equalsIgnoreCase(return_code)){
                String appid = root.elementText("appid");
                pay.setAppid(appid);
                log.info("appid:"+appid);

                String mch_id = root.elementText("mch_id");
                pay.setMch_id(mch_id);
                log.info("mch_id:"+mch_id);

                String nonce_str = root.elementText("nonce_str");
                pay.setNonce_str(nonce_str);
                log.info("nonce_str:"+nonce_str);

                String device_info = root.elementText("device_info");
                pay.setDevice_info(device_info);
                log.info("device_info:"+device_info);

                String sign = root.elementText("sign");
                pay.setSign(sign);
                log.info("sign:"+sign);

                String result_code = root.elementText("result_code");
                pay.setResult_code(result_code);
                log.info("result_code:"+result_code);

                if("SUCCESS".equalsIgnoreCase(result_code)){
                    String openid = root.elementText("openid");
                    pay.setOpenid(openid);
                    log.info("openid:"+openid);

                    String is_subscribe = root.elementText("is_subscribe");
                    pay.setIs_subscribe(is_subscribe);
                    log.info("is_subscribe:"+is_subscribe);

                    String trade_type = root.elementText("trade_type");
                    pay.setTrade_type(trade_type);
                    log.info("trade_type:"+trade_type);

                    String bank_type = root.elementText("bank_type");
                    pay.setBank_type(bank_type);
                    log.info("bank_type:"+bank_type);

                    String total_fee = root.elementText("total_fee");
                    pay.setTotal_fee(Integer.parseInt(total_fee));
                    log.info("total_fee:"+total_fee);

                    String coupon_fee = root.elementText("coupon_fee");
                    if(coupon_fee!=null&&!"".equals(coupon_fee)){
                        pay.setCoupon_fee(Integer.parseInt(coupon_fee));
                    }
                    log.info("coupon_fee:"+coupon_fee);

                    String fee_type = root.elementText("fee_type");
                    pay.setFee_type(fee_type);
                    log.info("fee_type:"+fee_type);

                    String transaction_id = root.elementText("transaction_id");
                    pay.setTransaction_id(transaction_id);
                    log.info("transaction_id:"+transaction_id);

                    String out_trade_no = root.elementText("out_trade_no");
                    pay.setOut_trade_no(out_trade_no);
                    log.info("out_trade_no:"+out_trade_no);

                    String attach = root.elementText("attach");
                    pay.setAttach(attach);
                    log.info("attach:"+attach);

                    String time_end = root.elementText("time_end");
                    pay.setTime_end(time_end);
                    log.info("attach:"+attach);

                }else{
                    String err_code = root.elementText("err_code");
                    pay.setErr_code(err_code);
                    log.info("err_code:"+err_code);

                    String err_code_des = root.elementText("err_code_des");
                    pay.setErr_code_des(err_code_des);
                    log.info("err_code_des:"+err_code_des);
                }
            }else{
                String return_msg = root.elementText("return_msg");
                pay.setReturn_msg(return_msg);
                log.info("return_msg:"+return_msg);
            }
        }
        log.info("pay.toString():"+pay.toString());
        if("SUCCESS".equalsIgnoreCase(pay.getReturn_code()) && "SUCCESS".equalsIgnoreCase(pay.getResult_code())){
            //获取参数
            boolean flage=resultDo(pay.getAttach(),pay.getOut_trade_no());
            if(flage){
                buff.append("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[支付成功]]></return_msg></xml>");
            }else{
                buff.append("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>");
            }
        }else{
            buff.append("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>");
        }
        log.info("out :"+buff.toString());
        out.print(buff.toString());
    }


    public Boolean resultDo(String formIdParams,String payNo){
        log.info("formIdParams is "+formIdParams);
        String[] params=formIdParams.split(",");
        String type=params[0];
        String id=params[1];
        boolean flage=false;

        return flage;
    }


    //从输入流读取post参数
    protected String readStreamParameter(ServletInputStream in){
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader=null;
        try{
            reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
            String line=null;
            while((line = reader.readLine())!=null){
                buffer.append(line);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(null!=reader){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }





}
